import math
from typing import Any

from error import *
from symbol_table import SymbolTable
from tokens import *
from ast_node import *
from context import *
from result import *


class Value(object):
    def __init__(self):
        self.context = None
        self.pos_end = None
        self.pos_start = None
        self.set_pos()  # 报错的位置
        self.set_context()  # 方便定义错误, 报错的上下文

    def set_pos(self, pos_start: Position = None, pos_end: Position = None) -> 'Value':
        self.pos_start = pos_start
        self.pos_end = pos_end
        return self

    def set_context(self, context=None) -> 'Value':
        self.context = context
        return self

    def illegal_operation(self, other=None):
        """
        用于报错
        :param other:
        :return:
        """
        if not other:
            other = self
        return RunTimeError(
            self.pos_start, self.pos_end,
            "非法操作",
            self.context
        )


class Number(Value):
    """扩展数字类型, 用于包裹解释器的输出值"""
    # 定义静态类型
    PI = None
    false = None
    true = None
    null = None

    def __init__(self, value):
        super().__init__()
        self.value = value

    def added_by(self, other: 'Number') -> ('Number', Error):
        """
        加法
        :param other:
        :return:
        """
        if isinstance(other, Number):
            return Number(self.value + other.value).set_context(self.context), None
        else:
            return None, self.illegal_operation(other)

    def subbed_by(self, other: 'Number') -> ('Number', Error):
        """
        减法
        :param other:
        :return:
        """
        if isinstance(other, Number):
            return Number(self.value - other.value).set_context(self.context), None
        else:
            return None, self.illegal_operation(other)

    def multed_by(self, other: 'Number') -> ('Number', Error):
        """
        乘法
        :param other:
        :return:
        """
        if isinstance(other, Number):
            return Number(self.value * other.value).set_context(self.context), None
        else:
            return None, self.illegal_operation(other)

    def dived_by(self, other: 'Number') -> ('Number', Error):
        """
        除法
        :param other:
        :return:
        """
        if isinstance(other, Number):
            if other.value == 0:
                return None, RunTimeError(other.pos_start, other.pos_end, '分母不可为0', self.context)
            return Number(self.value / other.value).set_context(self.context), None
        else:
            return None, self.illegal_operation(other)

    def powed_by(self, other: 'Number') -> ('Number', Error):
        """
        幂运算
        :param other:
        :return:
        """
        if isinstance(other, Number):
            return Number(self.value ** other.value).set_context(self.context), None
        else:
            return None, self.illegal_operation(other)

    def get_comparison_ee(self, other: 'Number') -> ('Number', Error):
        """
        等于逻辑运算
        :param other:
        :return:
        """
        if isinstance(other, Number):
            return Number(int(self.value == other.value)).set_context(self.context), None
        else:
            return None, self.illegal_operation(other)

    def get_comparison_ne(self, other: 'Number') -> ('Number', Error):
        """
        不等于逻辑运算
        :param other:
        :return:
        """
        if isinstance(other, Number):
            return Number(int(self.value != other.value)).set_context(self.context), None
        else:
            return None, self.illegal_operation(other)

    def get_comparison_lt(self, other: 'Number') -> ('Number', Error):
        """
        小于逻辑运算
        :param other:
        :return:
        """
        if isinstance(other, Number):
            return Number(int(self.value < other.value)).set_context(self.context), None
        else:
            return None, self.illegal_operation(other)

    def get_comparison_gt(self, other: 'Number') -> ('Number', Error):
        """
        大于逻辑运算
        :param other:
        :return:
        """
        if isinstance(other, Number):
            return Number(int(self.value > other.value)).set_context(self.context), None
        else:
            return None, self.illegal_operation(other)

    def get_comparison_lte(self, other: 'Number') -> ('Number', Error):
        """
        小于等于逻辑运算
        :param other:
        :return:
        """
        if isinstance(other, Number):
            return Number(int(self.value <= other.value)).set_context(self.context), None
        else:
            return None, self.illegal_operation(other)

    def get_comparison_gte(self, other: 'Number') -> ('Number', Error):
        """
        大于等于逻辑运算
        :param other:
        :return:
        """
        if isinstance(other, Number):
            return Number(int(self.value >= other.value)).set_context(self.context), None
        else:
            return None, self.illegal_operation(other)

    def and_by(self, other: 'Number') -> ('Number', Error):
        """
        且运算
        :param other:
        :return:
        """
        if isinstance(other, Number):
            return Number(int(self.value and other.value)).set_context(self.context), None
        else:
            return None, self.illegal_operation(other)

    def or_by(self, other: 'Number') -> ('Number', Error):
        """
        或运算
        :param other:
        :return:
        """
        if isinstance(other, Number):
            return Number(int(self.value or other.value)).set_context(self.context), None
        else:
            return None, self.illegal_operation(other)

    def not_by(self, other: 'Number') -> ('Number', Error):
        """
        非运算
        :param other:
        :return:
        """
        if isinstance(other, Number):
            return Number(int(1 if self.value == 0 else 0)).set_context(self.context), None
        else:
            return None, self.illegal_operation(other)

    def copy(self):
        """
        深拷贝
        :return:
        """
        copy = Number(self.value)
        copy.set_pos(self.pos_start, self.pos_end)
        copy.set_context(self.context)
        return copy

    def is_true(self):
        return self.value != 0

    def __repr__(self):
        return str(self.value)


####################
# built variable 内建变量
####################

Number.null = None
Number.false = Number(0)
Number.true = Number(1)
Number.PI = Number(math.pi)


class String(Value):
    """用于扩展String字符串"""

    def __init__(self, value):
        super().__init__()
        self.value = value

    def copy(self):
        return String(self.value).set_pos(self.pos_start, self.pos_end).set_context(self.context)

    def added_by(self, other: 'String') -> ('String', Error):
        """
        字符串拼接
        :param other:
        :return:
        """
        if isinstance(other, String):
            return String(self.value + other.value).set_context(self.context), None
        else:
            return None, self.illegal_operation(other)

    def multed_by(self, other: 'String') -> ('String', Error):
        """
        复制多个字符串
        :param other:
        :return:
        """
        if isinstance(other, String):
            return String(self.value * other.value).set_context(self.context), None
        else:
            return None, self.illegal_operation(other)

    def is_true(self):
        return len(self.value) > 0

    def __repr__(self):
        return f'{self.value}'


class List(Value):
    """用于支持列表"""

    def __init__(self, element_nodes: list[Value]):
        """
        函数操作对象
        :param element_nodes: 元素列表
        """
        super().__init__()
        self.elements = element_nodes

    def added_by(self, other: 'Value') -> ('List', Error):
        """
        加法
        :param other:
        :return:
        """
        new_list = self.copy()
        new_list.elements.append(other)
        return new_list, None

    def subbed_by(self, other: 'Number') -> ('List', Error):
        """
        减法
        :param other:
        :return:
        """
        if isinstance(other, Number):
            new_list = self.copy()
            try:
                new_list.elements.pop(other.value)
                return new_list, None
            except:
                return None, RunTimeError(
                    other.pos_start, other.pos_end,
                    "超出下标", self.context
                )
        else:
            return None, self.illegal_operation(other)

    def multed_by(self, other: 'List') -> ('List', Error):
        """
        乘法
        :param other:
        :return:
        """
        if isinstance(other, List):
            new_list = self.copy()
            new_list.elements.extend(other.elements)
            return new_list, None
        else:
            return None, self.illegal_operation(other)

    def dived_by(self, other: 'Number') -> ('List', Error):
        """
        除法
        :param other:
        :return:
        """
        if isinstance(other, Number):
            try:
                return self.elements[other.value], None
            except:
                return None, RunTimeError(
                    other.pos_start, other.pos_end,
                    "超出下标", self.context
                )
        else:
            return None, self.illegal_operation(other)

    def copy(self):
        new_list = self.elements[:]
        return List(new_list).set_context(self.context).set_pos(self.pos_start, self.pos_end)

    def __repr__(self):
        return f'[{", ".join([str(x) for x in self.elements])}]'
